﻿using Test30.Core;

namespace Test30.Engine
{
    public class Fov
    {
        public const int MaxDistance = 26;
        public static void RefreshExplored(Vec position, Dungeon dungeon)
        {
            // figure out which ones need to be looked at
            Rect bounds = new Rect(position - MaxDistance, new Vec(MaxDistance * 2 + 1, MaxDistance * 2 + 1));

            // stay in bounds
            bounds = bounds.Intersect(dungeon.Bounds);

            foreach (Vec pos in bounds)
            {
                Tile tile = dungeon.Tiles[pos];

                if (tile.IsVisible && tile.IsLit && !tile.IsExplored)
                {
                    dungeon.SetTileExplored(pos);
                }
            }
        }
        public static void RefreshVisibility(Vec position, Dungeon dungeon)
        {
            for (int octant = 0; octant < 8; octant++)
            {
                RefreshOctant(position, octant, dungeon);
            }
            dungeon.SetTileVisible(position, true);
        }

        private static void RefreshOctant(Vec start, int octant, Dungeon dungeon)
        {
            Vec rowInc = Vec.Zero;
            Vec colInc = Vec.Zero;

            switch (octant)
            {
                case 0: rowInc.Y = -1; colInc.X = 1; break;
                case 1: rowInc.X = 1; colInc.Y = -1; break;
                case 2: rowInc.X = 1; colInc.Y = 1; break;
                case 3: rowInc.Y = 1; colInc.X = 1; break;
                case 4: rowInc.Y = 1; colInc.X = -1; break;
                case 5: rowInc.X = -1; colInc.Y = 1; break;
                case 6: rowInc.X = -1; colInc.Y = -1; break;
                case 7: rowInc.Y = -1; colInc.X = -1; break;
            }

            // cache for performance
            Rect bounds = dungeon.Bounds;

            for (int row = 1; row < MaxDistance; row++)
            {
                Vec pos = start + (rowInc * row);

                if (!bounds.Contains(pos)) break;

                for (int col = 0; col <= row; col++)
                {
                    dungeon.SetTileVisible(pos, false);

                    pos += colInc;

                    if (!bounds.Contains(pos)) break;
                }
            }
        }
    }
}
